package common.inject;

import java.util.HashMap;
import java.util.Map;
import org.apache.commons.lang.StringUtils;

public class Injector
{
    private static Injector instance;

    Map<Key, Provider> providerMap = new HashMap<Key, Provider>();
    Map<Key, Object> signleInstanceMap = new HashMap<Key, Object>();

    private Injector()
    {

    }

    public static Injector getInjector()
    {
        if (null == instance)
        {
            instance = new Injector();
        }
        return instance;
    }

    public <T> Provider<T> bind(Class<T> clazz)
    {
        Key key = madeKey(clazz, null);
        if (providerMap.containsKey(key))
        {
            return providerMap.get(key);
        }
        return bind(clazz, null);
    }

    public <T> Provider<T> bind(Class<T> clazz, String name)
    {
        Key key = madeKey(clazz, null);
        if (providerMap.containsKey(key))
        {
            return providerMap.get(key);
        }
        ClassProvider cp = new ClassProvider();
        cp.bind(clazz, name);
        return bind(cp);
    }

    public <T> Provider<T> bind(Provider provider)
    {
        providerMap.put(provider.getKey(), provider);
        return provider;
    }

    public <T> T create(Class<T> clazz)
    {
        return create(clazz, null);
    }

    public <T> T create(Class<T> clazz, String name)
    {
        Key key = madeKey(clazz, name);
        if (signleInstanceMap.containsKey(key))
        {
            return (T) signleInstanceMap.get(key);
        }
        Provider<T> provider = null;
        if (!providerMap.containsKey(key))
        {
            provider = bind(clazz, name);
        }
        T t = provider.get();
        // TODO select scope if signle save it to below instanceMap.
        signleInstanceMap.put(key, t);
        return t;
    }

    private <T> Key madeKey(Class<T> clazz, String name)
    {
        Key key = StringUtils.isBlank(name) ? new Key(clazz) : new Key(clazz, name);
        return key;
    }

}
